#include "heaptimer.h"
//HeapTimer类的向上调整函数
void HeapTimer::siftup_(size_t i)
{
    //断言i大于等于0，并且小于堆的大小
    assert(i >= 0 && i < heap_.size());
    //j是i的父节点
    size_t j = (i-1)/2;
    //循环判断j是否大于等于0
    while(j >= 0)
    {
        //如果父节点小于子节点，就不需要向上调整
        if(heap_[j] < heap_[i]){break;}
        //如果父节点大于子节点，就交换父节点和子节点
        SwapNode_(i,j);
        //让i成为j
        i = j;
        //让j成为i的父节点
        j = (i-1)/2;
    }
}

//HeapTimer类的交换节点函数
void HeapTimer::SwapNode_(size_t i,size_t j)
{
    //判断i和j是否大于等于0，并且小于堆的大小
    assert(i >= 0 && i < heap_.size());
    assert(j >= 0 && j < heap_.size());
    //heap_是一个vector，交换vector里面i和j的元素
    std::swap(heap_[i],heap_[j]);
    //ref_是一个unordered_map，交换unordered_map里面i和j的元素
    ref_[heap_[i].id] = i;
    ref_[heap_[j].id] = j;
}
//向下调整函数
bool HeapTimer::siftdown_(size_t index,size_t n)
{
    //断言index大于等于0，并且小于堆的大小
    assert(index >= 0 && index < heap_.size());
    //断言n大于等于0，并且小于等于堆的大小
    assert(n >= 0 && n <= heap_.size());
    //定义一个i，初始值是index
    size_t i = index;
    //定义一个j，初始值是i的左孩子节点
    size_t j = i*2 + 1;
    //循环判断j是否小于n
    while(j < n)
    {
        //如果右孩子节点存在，并且右孩子小于左孩子，则将j指向右孩子
        if(j + 1 < n && heap_[j+1] < heap_[j]) j++;
        //如果父节点小于右节点，就不需要向下调整
        if(heap_[i] < heap_[j]) break;
        //如果父节点大于右节点，就交换父节点和右节点
        SwapNode_(i,j);
        //向下调整，让i成为j
        i = j;
        //让j成为i的左孩子节点
        j = i*2 + 1;
    }
    //如果i大于index，说明向下调整完毕了
    return i > index;
}
//添加定时器函数
void HeapTimer::add(int id,int timeout,const TimeoutCallBack& cb)
{
    //断言id是否大于等于0
    assert(id >= 0);
    //创建一个size_t类型的变量i，用于存储定时器在堆中的索引
    size_t i;
    //如果ref_中不存在id，说明是这是一个新的定时器
    if(ref_.count(id) == 0)
    {
        //将i赋值为堆的大小
        i = heap_.size();
        //将id和i建立映射关系
        ref_[id] = i;
        //在堆中添加一个定时器节点，节点的id是id，过期时间是当前时间加上超时时间，回调函数是cb
        heap_.push_back({id,Clock::now() + MS(timeout),cb});
        //向上调整，让新添加的定时器节点，在堆中找到合适的位置
        siftup_(i);
    }
    //新添加的id如果在ref_中已经存在了
    else
    {
        //将i赋值为id在ref_中的索引
        i = ref_[id];
        //将堆中id的过期时间更新为当前时间加上超时时间
        heap_[i].expire = Clock::now() + MS(timeout);
        //将堆中id的回调函数更新为cb
        heap_[i].cb = cb;
        //如果向下调整失败，就向上调整
        if(!siftdown_(i,heap_.size()))
        {
            //向上调整
            siftup_(i);
        }
    }
}
//超时之后干活的函数
void HeapTimer::doWork(int id)
{
    //如果堆是空的或者ref_中不存在id，就直接返回
    if(heap_.empty() || ref_.count(id) == 0)
    {
        //返回
        return;
    }
    //定义一个变量i，用于存储定时器id在堆中的索引
    size_t i = ref_[id];
    //定义一个定时器节点node，用于存储定时器节点
    TimerNode node = heap_[i];
    //调用定时器节点的回调函数
    node.cb();
    //删除定时器节点
    del_(i);
}
//根据索引删除定时器节点的函数
void HeapTimer::del_(size_t index)
{
    //断言堆不是空的，并且索引大于等于0，并且索引小于堆的大小
    assert(!heap_.empty() && index >= 0 && index < heap_.size());
    //定义一个变量i，用于存储索引
    size_t i = index;
    //定义一个变量n，用于存储堆的大小减1（堆中元素的实际个数）
    size_t n = heap_.size() - 1;
    //断言i小于等于n
    assert(i <= n);
    //如果i小于n
    if(i < n)
    {
        //交换i和n的位置
        SwapNode_(i,n);
        //如果向下调整失败，就向上调整
        if(!siftdown_(i,n))
        {
            //向上调整
            siftup_(i);
        }
    }
    //删除定时器映射中，最后一个节点的映射关系
    ref_.erase(heap_[n].id);
    //删除堆中最后一个节点
    heap_.pop_back();
}
//调整定时器函数
void HeapTimer::adjust(int id,int timeout)
{
    //断言堆不是空的，并且ref_中存在id的映射关系
    assert(!heap_.empty() && ref_.count(id) > 0);
    //将堆中id的过期时间更新为当前时间加上超时时间
    heap_[ref_[id]].expire = Clock::now() + MS(timeout);
    //向下调整
    siftdown_(ref_[id],heap_.size());
}
//超时处理函数
void HeapTimer::tick()
{
    //如果堆是空的，就直接返回
    if(heap_.empty())
    {
        //直接返回
        return;
    }
    //循环判断堆是不是空的
    while(!heap_.empty())
    {
        //获取堆顶元素
        TimerNode node = heap_.front();

        if(std::chrono::duration_cast<MS>(node.expire - Clock::now()).count() > 0)
        {
            //跳出循环
            break;
        }
        //调用回调函数
        node.cb();
        //删除堆顶元素
        pop();
    }
}
//删除堆顶元素的函数
void HeapTimer::pop()
{
    //断言堆不是空的
    assert(!heap_.empty());
    //删除堆顶元素
    del_(0);
}
//清空定时器函数
void HeapTimer::clear()
{
    //清空定时器映射
    ref_.clear();
    //清空定时器堆
    heap_.clear();
}
//获取下一个定时器的超时时间
int HeapTimer::GetNextTick()
{
    //看堆顶元素是否超时
    tick();
    //定义一个res变量，用于存储下一个定时器的超时时间
    size_t res = -1;
    //如果堆不是空的
    if(!heap_.empty())
    {
        //获取堆顶元素的超时时间
        res = std::chrono::duration_cast<MS>(heap_.front().expire - Clock::now()).count();
        //如果超时时间小于0，说明堆顶元素已经超时，将超时时间设置为0
        if(res < 0)
        {
            //说明堆顶元素已经超时，将超时时间设置为0
            res = 0;
        }
    }
    //返回下一个定时器的超时时间
    return res;
}